
from jili.core.printlog import print
import pandas as pd
def getbackwindows(data,m=5):
    if isinstance(data,dict):
        return list(data.values())[-m:]
    elif isinstance(data,list):
        return data[-m:]
    else:
        return []
class dataset():
    def __init__(self,data):
        if isinstance(data,dict):
            self.key=list(data.keys())
            self.values=list(data.values())
            self.size=len(data)
        elif isinstance(data,list):
            self.key=[]
            self.values=data
            self.size=len(data)
            if "timekey" in data[0].keys:
                for i in data:
                    self.key.append(i["timekey"])
            else:
                self.key=range(0,len(data))
        else:
            self.key=[]
            self.data=[]
            self.size=len(data)
    def __getitem__(self,index):
        if index in self.key:
            n=self.key.index(index)
            return self.values[n]
        else:
            return {}
    def getbackwindows(self,index,m=5):
        if index in self.key:
            n=self.key.index(index)+1
            nn=n-m
            if nn<0:
                nn=0
            return self.values[nn:n]
        else:
            return []
    def getforwardwindows(self,index,m=5):
        if index in self.key:
            n=self.key.index(index)
            nn=n+m
            return self.values[n:nn]
        else:
            return []
class backwindows(object):
    def __init__(self,data,m=5):
        self.n=0
        self.m=m
        if isinstance(data,dict):
            self.values=list(data.values())
            self.size=len(data)
        elif isinstance(data,list):
            self.values=data
            self.size=len(data)
        elif isinstance(data,pd.DataFrame):
            self.values=data.to_dict("records")
            self.size=len(self.values)
        else:
            self.data=[]
            self.size=0
    def __iter__(self):
        return self
    def __next__(self): 
        if self.n < self.size: 
            self.n=self.n+1
            nn=self.n-self.m
            if nn<0:
                nn=0
            return self.values[nn:self.n]
        raise StopIteration()
class windows(object):
    def __init__(self,data,m=2,fx=0):
        self.fx=fx
        self.n=0
        self.m=m
        if isinstance(data,dict):
            self.values=list(data.values())
            self.size=len(data)
        elif isinstance(data,list):
            self.values=data
            self.size=len(data)
        elif isinstance(data,pd.DataFrame):
            self.values=data.to_dict("records")
            self.size=len(self.values)
        else:
            self.data=[]
            self.size=0
    def __iter__(self):
        return self
    def __next__(self):
        if self.n < self.size:
            if self.fx!=0:
                nn=self.n+self.m
                r=self.values[self.n:nn]
                self.n=self.n+1
                return r
            else:
                n1 = self.n - self.m
                if n1<0:
                    n1=0
                n2=self.n+1
                r = self.values[n1:n2]
                self.n = self.n + 1
                return r
        raise StopIteration()
class forwardwindows(object):
    def __init__(self,data,m=5):
        self.n=0
        self.m=m
        if isinstance(data,dict):
            self.values=list(data.values())
            self.size=len(data)
        elif isinstance(data,list):
            self.values=data
            self.size=len(data)
        elif isinstance(data,pd.DataFrame):
            self.values=data.to_dict("records")
            self.size=len(self.values)
        else:
            self.data=[]
            self.size=0
    def __iter__(self):
        return self
    def __next__(self): 
        if self.n < self.size: 
            nn=self.n+self.m
            r=self.values[self.n:nn]
            self.n=self.n+1
            return r
        raise StopIteration()
class forwardbatch(object):
    def __init__(self,data,m=5):
        self.n=0
        self.m=m
        if isinstance(data,dict):
            self.values=list(data.values())
            self.size=len(data)
        elif isinstance(data,list):
            self.values=data
            self.size=len(data)
        elif isinstance(data,pd.DataFrame):
            self.values=data.to_dict("records")
            self.size=len(self.values)
        else:
            self.data=[]
            self.size=0
    def __iter__(self):
        return self
    def __next__(self):
        if self.n < self.size:
            nn=self.n+self.m
            r=self.values[self.n:nn]
            self.n=self.n+self.m
            return r
        raise StopIteration()
def P(c,x):
    """
    计算x在a中的概率密度    P(x/a)
    要求:a：dict,list   成员 为：dict x :dict      list  x:list
    """
    ct=0
    total=10000
    if isinstance(c,dict):
        a=list(c.values())
    else:
        a=c
    if isinstance(a,list):
        b=a[0]
        total=len(a)
        if isinstance(b,dict):
            if isinstance(x,dict):
                for i in a:
                    istrue=True
                    for j in x.keys():
                        if j in x.keys():
                            if i[j]!=x[j]:
                                istrue=False
                        else:
                            istrue=False
                    if istrue:
                        ct=ct+1
        elif isinstance(b,list):
            if isinstance(x,list):
                for i in a:
                    istrue=True
                    for j in range(len(x)):
                        if i[j]!=x[j]:
                            istrue=False
                    if istrue:
                        ct=ct+1
        else:
            for i in a:
                if i==x:
                    ct=ct+1
    return ct/total
def F(a,x,fx=">"):
    ct=0
    total=len(a)
    if fx==">":
        for i in a:
            if  i>x:
                ct=ct+1
    elif fx==">=":
        for i in a:
            if  i>=x:
                ct=ct+1
    elif fx=="<":
        for i in a:
            if  i<x:
                ct=ct+1
    elif fx=="<=":
        for i in a:
            if  i<=x:
                ct=ct+1
    else:
        for i in a:
            if  i==x:
                ct=ct+1
    return ct/total
def F_distribution(a,x):
    y=[]
    for i in x:
        r=F(a,i,">=")+F(a,-i,"<=")
        y.append(r)
    return y
from functools import wraps
import time
def costtimes (func):
    @wraps(func)
    def wrapper(*args,**kwargs):
        start = time.clock()
        ret = func(*args,**kwargs)
        print("costtimes:",(time.clock() - start)*1000,"ms")
        return ret
    return wrapper
@costtimes
def get_op_list(op):
    import itertools
    r1=[]
    for k,v in op.items():
        for i in v:
            r1.append((k,i))
    r2=[]
    for i in itertools.combinations(r1, len(op)):
        r2.append(i)
    r1=[]
    for i in r2:
        t=[]
        for j in i:
            if j[0] not in t:
                t.append(j[0])
        check=True
        for k in op.keys():
            if k not in t:
                check=False
        if check:
            r1.append(i)
    return r1
def costtime(call,arg):
    import time
    start = time.clock()
    call(arg)
    return time.clock() - start

import pandas as pd
import numpy as np
class calcor_base:
    def __init__(self,ta_arg={},ispass_conlimit=False):
        """

        Args:
            ta_arg:

        self.name=""
        self.group=""
        self.display_name=""
        """
        # self.out=[]
        # self.input=[]
        # self.parameters={}
        self.name = type(self).__name__
        self.batch=0
        self.lookback=0
        self.isoneout=True
        self.lasttimekey = None
        self.hisbars = {}
        self.outall=ta_arg.get("outall",True)
        self.default=ta_arg.get("default",None)
        self.ispretimekey=False
        if ispass_conlimit:
            self.islimit_flag=0
            self.add_bar = self.add_bar_1
            self.pre_b={}
        else:
            self.add_bar=self.add_bar_0
        self.ispass_conlimit=ispass_conlimit
        if ta_arg:
            self.setarg(ta_arg)
    def drop_ta(self):
        pass
    def init_ta(self):
        pass
    def setarg(self, ta_arg):
        if "batch" in ta_arg.keys():
            self.batch = ta_arg["batch"]
        if "arg" in ta_arg.keys():
            self.set_parameters(ta_arg["arg"])
            if "timeperiod" in ta_arg["arg"].keys():
                if ta_arg["arg"]["timeperiod"] > self.batch:
                    self.batch = ta_arg["arg"]["timeperiod"]
        if "fillna" in ta_arg.keys():
            self.fillna=ta_arg["fillna"]
        else:
            self.fillna=None
        if "out" in ta_arg.keys():
            self.set_output_names(ta_arg["out"])
        if len(self.out) > 1:
            self.isoneout = False
        if "input" in ta_arg.keys():
            self.set_input_names(ta_arg["input"])
    def get_input_names(self):
        return self.input
    def get_output_names(self):
        return self.out
    def get_parameters(self):
        return self.parameters
    def set_parameters(self,args):
        self.parameters.update(args)
    def set_input_names(self,input_names):
        if isinstance(input_names,dict):
            input_names=list(input_names.values())
        n=len(input_names)
        for i in range(n):
            self.input[i]=input_names[i]

    def set_output_names(self,output_names):
        n = len(output_names)
        for i in range(n):
            self.out[i] = output_names[i]

    def info(self):
        t = {}
        t["cmd"] = self.name
        t["arg"] = self.parameters
        t["input"] = self.input
        t["out"] = self.out
        t["batch"] = self.batch
        return t
    def sethisbar(self, bars):
        if isinstance(bars, list):
            self.lasttimekey = bars[-1]["timekey"]
            hisbars = pd.DataFrame(bars)
            for i in self.input:
                self.hisbars[i] = np.array(hisbars[i], dtype=np.double)
        elif isinstance(bars, pd.DataFrame):
            self.lasttimekey = bars["timekey"][-1].to_pydatetime()
            for i in self.input:
                self.hisbars[i] = np.array(bars[i], dtype=np.double)
    def getinputlist(self,bar):
        input=[]
        for i in self.input:
            input.append(bar.get(i,0))
        return input
    def getdata(self,data,key):
        if "." in key:
            for i in key.split("."):
                data=data[i]
                if data   is None:
                    data = np.nan
            return data
        else:
            if data[key]  is None:
                return np.nan
            else:
                return data[key]
    def setdata(self,data,t):
        for k, v in t.items():
            if "." in k:
                d = data
                l = k.split(".")
                n = len(l)
                nn = 0
                for i in l:
                    nn = nn + 1
                    if nn < n:
                        if i not in d.keys():
                            d[i] = {}
                        d = d[i]
                    else:
                        d[i] = v
            else:
                data[k] = v
        return data
    def add_data(self,data,timekey):
        if self.lasttimekey:
            if timekey:
                tk=timekey
            else:
                tk = data["timekey"]
            if tk == self.lasttimekey:
                for i in self.input:
                    data0 = self.hisbars[i]
                    n = self.hisbars[i].size - 1
                    data0[n] = self.getdata(data,i)
            else:
                self.lasttimekey = tk
                for i in self.input:
                    n = self.hisbars[i].size

                    if self.batch > n:
                        self.hisbars[i] = np.append(self.hisbars[i], [self.getdata(data,i)], axis=0)
                    else:
                        self.hisbars[i] = np.delete(self.hisbars[i], 0, 0)
                        self.hisbars[i] = np.append(self.hisbars[i], [self.getdata(data,i)], axis=0)
        else:
            if timekey:
                self.lasttimekey=timekey
            else:
                self.lasttimekey = data["timekey"]
            for i in self.input:
                data0 = [self.getdata(data,i)]
                self.hisbars[i] = np.array(data0, dtype=np.double)
        input = self.input[0]
        n = self.hisbars[input].size
        return n
    def ondata(self,data,timekey=None):#支持多层级数据检索与
        n=self.add_data(data,timekey)
        if n >= self.batch:
            # self.ta.set_input_arrays(self.hisbars)
            outputs=self.calc()
            if self.isoneout:
                try:
                    t = {self.out[0]: outputs}
                except Exception as e:
                    print(e)
            else:
                n = 0
                t = {}
                for i in self.out:
                    if i != "_":
                        t[i] = outputs[n]
                    n = n + 1
        else:
            t = {}
            for i in self.out:
                if i != "_":
                    t[i] = self.default
        if self.outall:
            return self.setdata(data, t)
        else:
            return t
    def get_fillna(self,a,data):
        if pd.isna(a):
            if self.fillna  is None:
                if isinstance(data,list):
                    if data:
                        return data[-1]
                else:
                    return data[-1]

            else:
                return self.fillna
        return a
    def add_bar_0(self,bar,tk):
        if self.lasttimekey:
            if tk == self.lasttimekey:
                for i in self.input:
                    data = self.hisbars[i]
                    n = self.hisbars[i].size-1
                    d0 = self.get_fillna(bar[i], data)
                    data[n] = d0
            else:
                self.lasttimekey = tk
                for i in self.input:
                    n = self.hisbars[i].size
                    d0 = self.get_fillna(bar[i], self.hisbars[i])
                    if self.batch > n:
                        self.hisbars[i]=np.append(self.hisbars[i],[d0],axis=0)
                    else:
                        self.hisbars[i] = np.delete(self.hisbars[i],0,0)
                        self.hisbars[i] = np.append(self.hisbars[i], [d0], axis=0)
        else:
            self.lasttimekey = tk
            for i in self.input:
                data = [bar[i]]
                self.hisbars[i] = np.array(data, dtype=np.double)
        input=self.input[0]
        n = self.hisbars[input].size
        return n
    def add_bar_1(self,bar,tk):
        if self.pre_b:
            if bar["open"]==bar["close"]==bar["high"]==bar["low"]==self.pre_b["clsoe"]:
                self.islimit_flag=self.islimit_flag+1
                if self.islimit_flag>2:
                    if self.hisbars:
                        input = self.input[0]
                        n = self.hisbars[input].size
                    else:
                        n = 0
                    return n
            else:
                self.islimit_flag=0
        if self.lasttimekey:
            if tk == self.lasttimekey:
                for i in self.input:
                    data = self.hisbars[i]
                    n = self.hisbars[i].size-1
                    d0 = self.get_fillna(bar[i], data)
                    data[n] = d0
            else:
                self.lasttimekey = tk
                for i in self.input:
                    n = self.hisbars[i].size
                    d0 = self.get_fillna(bar[i], self.hisbars[i])
                    if self.batch > n:
                        self.hisbars[i]=np.append(self.hisbars[i],[d0],axis=0)
                    else:
                        self.hisbars[i] = np.delete(self.hisbars[i],0,0)
                        self.hisbars[i] = np.append(self.hisbars[i], [d0], axis=0)
        else:
            self.lasttimekey = tk
            for i in self.input:
                data = [bar[i]]
                self.hisbars[i] = np.array(data, dtype=np.double)
        if self.hisbars:
            input=self.input[0]
            n = self.hisbars[input].size
        else:
            n=0
        self.pre_b=bar
        return n
    def onbar(self, bar,timekey=None):
        if timekey is not None:
            tk=timekey
        else:
            tk=bar["timekey"]
        n=self.add_bar(bar,tk)
        if n >= self.batch:
            # self.ta.set_input_arrays(self.hisbars)
            outputs = self.calc()
            if self.isoneout:
                try:
                    t={self.out[0]: outputs}
                except Exception as e:
                    print(e)
                    t = {self.out[0]: self.default}
            else:
                n = 0
                t = {}
                for i in self.out:
                    if i !="_":
                        t[i] = outputs[n]
                    n = n + 1
        else:
            t = {}
            for i in self.out:
                if i != "_":
                    t[i] = self.default
        if self.outall:
            bar.update(t)
            return bar
        else:
            return t

